// ===================代码模块=========================

// 我们所有的代码不能都写到一个文件里面;
// 分开文件，js--> 模块机制;
// js 加载代码的 require()
// step1: 加载指定的js代码，并执行;
require("./utils")
// 如果js代码已经被加载进来了，是不会执行的;
require("./utils")

// require 返回值, 返回加载进来的代码的module.exports 所指向的对象;
// 多次require同一个模块，都回返回这个module.exports;
var utils = require("./utils");
// console.log(ret); // 返回的是一个 {}, 因为你还没有指定module.exports导出的对象;
// console.log(ret(3, 4));
console.log(utils.add(3, 4));

/* 总结一下
require: 去加载指定的js代码;
require 会返回这个代码里面的module.exports,如果用户没有指定，module.export = {};
require 如果这个js代码已经被加载了，是不会再次装载执行的，但是仍然可以返回module.export所值的对象;
*/

// 一般我们会用和代码名字同名的变量，来接住require的返回值;
var test = require("./test");
console.log(test);
// end

// ===================this 机制=========================
function my_func(lhs, rhs) {
	console.log(this); // 使用this;
	console.log(lhs, rhs)
}

my_func(3 ,4); // 函数调用, this,可能是一个不确定的值;
// 函数.call: 显示的传递this
my_func.call({name: "blake"}, 4, 5);

// 表.key 来隐式的传递this;
var tools = {
	my_func: my_func,
}
tools.my_func(5 ,6); // 表.函数key() --> this--> 表


// 强制绑定this, 优先级式最高的;
// 函数.bind, 不会改变原来的函数对象的this,而是会产生一个新的函数对象，bind好了this
var new_func = my_func.bind({name: "blake"}); // 

new_func(6 ,7);

tools.my_func = new_func;
tools.my_func(7, 8); // this {name: "blake"}
my_func(8, 9) // 回答式一个强制绑定的表, 
// end 

// call 与bind 有什么区别呢？
// bind最牛的地方式什么？是绑定this的时候，
// 不是由调用者来决定的,回掉函数，你会明白这个意义;
// 
new_func.call({name: "blake_test"}, 9, 10)

// 再函数里面访问this, this是什么是由调用的环境来决定的, 不确定的，我们一般不使用;
// 显示的传递this, 函数.call(this对象, 参数)
// 隐士的传递this, 表.key_函数(参数), this--> 表;
// 强制bind this, 函数.bind(this对象): 产生一个强制bind this的新的函数对象;
// bind 优先级别是最高的;


// ===================new 与构造函数 机制=========================
function person(name, age) {
	this.name = name;
	this.age = age;
}
// 机制1 每一个函数对象都有一个表, prototype;
console.log(person.prototype);
person.prototype.get_age = function() {
	return this.age;
}
person.prototype.type = 1;

// 机制2: new 关键字 + 函数(参数)
// step1: 创建了一个新的表 {};
// step2: 创建的新的表--> this 传递，并调用person函数函数,进入person里面以后;
// person函数里面this --> 表;
// step3: person构造函数里面prototype这个表赋值到 新的表(this)的.__proto__
// step4: 返回这个新的表;
// 函数起的作用，构造出来 一个表， new 函数 --> 构造函数, 初始化表对象;
var blake = new person("Blake", 34);
console.log(blake);
var tom = new person("tom", 34);
console.log(tom);
var xiaoming = new person("xiaoming", 12);
console.log(xiaoming);
console.log(xiaoming.__proto__); // __proto__： get_age--> 函数对象;
// end

// 搜索机制;
// 当我们在一个表里面 使用里面key的时候,
// 首先我们会在表里面找, 如果找到就直接使用这个key,所对应的value;
// 如果没有找到，我们会去__proto__这个里面找，找到我们就使用;
// 进入函数的时候，如果没有强制绑定this,就会根据隐士的调用规则，把xiaoming---> this get_age
var ret = xiaoming.get_age()
ret = blake.get_age();
console.log(ret);

// person --> 类, new person --> 类构造出来的 实例;

// new person()
function new_person(name, age) {
	// step1:
	var instacne = {};
	// step2
	person.call(instacne, name, age);
	// step3:
	instacne.__proto__ = {};
	// step4: 将person里面的prototype这个表复制过来;
	for(var key in person.prototype) {
		instacne.__proto__[key] = person.prototype[key];
	}

	// step5
	return instacne;
}


var xiaohong = new_person("xiaohong1", 122);
console.log(xiaohong);


// step1 xiaohong 这个表里面找;
// step2 如果没找到,__proto__表里找--> 找到;
ret = xiaohong.get_age();
console.log(ret);


var xiaotian = {
	name: "blake",
	age: 3330,

	__proto__: {
		get_age: person.prototype.get_age,
	},
}

ret = xiaotian.get_age()
console.log(ret);